/////// type level ///////
type Red = { color: 'red' | `${string}red` };

type Transparent = { color: 'nonered' };

type MaybeColor = Transparent | Red;
let maybeColor: MaybeColor = { color: 'nonered' };
maybeColor;
//      ^?
type MixinColor = {
  [k in keyof (Transparent | Red)]: (Transparent | Red)[k];
};
let mixinColor: MixinColor = { color: 'red' };
// mixinColor.color;
//       ^?
{
  type MaybeColorKey = keyof MaybeColor;
  //           ^?

  type MixinColorKey = keyof MixinColor;
  //           ^?

  type Check = MaybeColorKey extends MixinColorKey ? true : false;
  //       ^?
  type CheckR = MixinColorKey extends MaybeColorKey ? true : false;
  //       ^?
}
type RemixColor = Transparent & Red;
//         ^?

let remixColor: RemixColor = { color: 'nonered' };
remixColor.color;
//          ^?

type ForceRemix = {
  //         ^?
  [k in keyof (Transparent & Red)]: (Transparent & Red)[k];
};

{
  type RemixColorKey = keyof RemixColor;
  //             ^?
  type ForceRemixKey = keyof ForceRemix;
  //            ^?
}
/////// type level end ///////
const none: {} = {};

type UnionNone = {} | { name: number };
// 类型的计算
// 1. 基础类型会被直接求值
// 2. 引用类型(除了空对象的交叉)，类型为惰性的值
// 3. 计算的最小对比单位是 一对kv
// 4. 每次计算都去相同的key计算(不存在则value拥有隐式never)

// ## 非求值的类型计算(联合/交叉)(惰性计算)  --- 特别地在值层面发挥特殊机制
// 联合|
// 1. 初始值可以为 (逆变)联合前的某个独立的类型，可以使下文中的值限定为这个类型
// 2. 两个对象的字段可以 都拥有定义，但此时无法简单访问(不可读)
// 3. value 的类型有交集：如果值符合具体那个，则取那个； 否则则取更抽象那个

// 交叉&
// 1. 初始值定义时必须拥有两个对象类型中 所有出现过的key的定义
// 2. 如果key都存在, 对value值求 交叉
// 3. value 的类型有交集：值的类型限定为最具体的那个
// 4. value 的类没有交集： **整体变为 never**

// ## 两个对象类型计算(联合/交叉)合并求值 (在类型层面就确认最终类型) --- 得到新的类型
// ### 参与类型收窄
// 联合|
// 1. 如果其中一个key不存在， 删除这个key
// 2. 如果key都存在，则这对kv为: key为保留key，value结果为两个value的联合
//> 联合的结果的上界为 {} (基元类型也适配)

// 交叉&
// 1. 如果其中一个key不存在， 保留存在的key
// 2. 如果key都存在(不显示为never)，则这对kv为: key为保留key，value结果为两个value的交叉, 如果交叉的结果为never，则整体变为never
//> 交叉的结果的下界为 never (基元类型也适配)

// > # 隐式地为 never: 类型层面未显示定义这个字段但是却访问这个字段，计算的表现结果为any，但是在参与计算时则实际是 never ({} 等价于 Record<never, never>)
type O = 1 | never;
